package prefix.platform.email;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import prefix.platform.Constants;
import prefix.platform.email.AbstractEmailEngine.EmailType;
import prefix.util.IOUtil;

public enum EmailTemplate {
    MessageHeader(EmailType.NONE),
    MessageFooter(EmailType.NONE),
    AdminAlert(EmailType.ADMIN, false); // For admin alerts

    protected static final String EMAIL_TEMPLATES_EXT = ".html";

    protected static Pattern propertyRegExp = Pattern.compile("\\$([a-z0-9\\._-]+)\\$", Pattern.CASE_INSENSITIVE);

    protected static final String EMAIL_RESOURCES_FILE_NAME = "emails";

    private EmailType type = EmailType.NONE;

    private boolean includeHeaderAndFooter = false;

    private EmailTemplate(EmailType type) {
        this.type = type;
    }

    private EmailTemplate(EmailType type, boolean includeHeaderAndFooter) {
        this.type = type;
        this.includeHeaderAndFooter = includeHeaderAndFooter;
    }

    public EmailType getType() {
        return type;
    }

    /**
     * Gets current template file name
     */
    public String getTemplateFile() {
        return getEmailTemplatesDir() + "/" + this.name() + EMAIL_TEMPLATES_EXT;
    }

    protected static String getEmailTemplatesDir() {
        return Constants.CONTENT_ROOT + "/emailTemplate";
    }

    /**
     * Get template contents
     */
    public String getContents() {
        StringBuffer contents = new StringBuffer();
        InputStreamReader reader = null;
        BufferedReader input = null;
        try {
            reader = new InputStreamReader(new FileInputStream(getTemplateFile()), "utf-8");
            input = new BufferedReader(reader);
            String line = null;
            while ((line = input.readLine()) != null) {
                contents.append(line);
                contents.append(System.getProperty("line.separator"));
            }
            return contents.toString();
        } catch (Exception ex) {
            return null;
        } finally {
            IOUtil.closeQuietly(input);
            IOUtil.closeQuietly(reader);
        }
    }

   

    /**
     * Builds a Message content based on the current template
     * 
     * @param vars
     *            variables to fill template placeholders
     * @return String
     */
    public String buildMessageContent(Map<String, String> vars) {

        String contents = getContents();

        try {
            if (contents != null) {

                // Load resource bundle, for now only Chinese is supported

                String body = "";
                // Append header
                if (includeHeaderAndFooter) {
                    body += replacePlaceholders(MessageHeader.getContents(), vars);
                }

                // Append body
                body += replacePlaceholders(contents, vars);

                // Append footer
                if (includeHeaderAndFooter) {
                    body += replacePlaceholders(MessageFooter.getContents(), vars);
                }

                return body;
            }
        } catch (Exception e) {
            // Error while building email
            e.printStackTrace();
        }
        return "";
    }

    /**
     * Replace vars and message properties in the given text
     * 
     * @param text
     * @param vars
     * @param bundle
     * @return
     */
    protected static String replacePlaceholders(String text, Map<String, String> vars) {
        // Replace twice to allow placeholders in vars
        String processed = replaceVars(text, vars);
        return processed;
    }

    /**
     * Replaces all occurrences of the given map keys by its corresponding
     * values in the provided text
     * 
     * @param text
     * @param vars
     * @return
     */
    protected static String replaceVars(String text, Map<String, String> vars) {
        for (String key : vars.keySet()) {
            String value = vars.get(key);
            if (value != null) {
                text = text.replaceAll(Matcher.quoteReplacement(key), Matcher.quoteReplacement(value));
            }
        }
        return text;
    }

    /**
     * Gets email parameters from vars or resource bundles
     */
    protected EmailParams getMessageParams(Map<String, String> vars) {
        EmailParams params = new EmailParams(vars);
        params.setSubject(this.name());
        return params;
    }

    /**
     * Builds a Message object based on the current template
     * 
     * @param toAddress
     *            target address
     * @param vars
     *            variables to fill template placeholders
     * @param session
     *            transport session
     * @return
     */
    public Message buildMessage(String toAddress, Map<String, String> vars, Session session) {

        String contents = getContents();

        try {
            if (contents != null) {

                // Get email params
                EmailParams params = getMessageParams(vars);

                Message msg = new MimeMessage(session);

                // Set subject
                msg.setSubject(replacePlaceholders(params.getSubject(), vars));

                // Set from
                msg.setFrom(new InternetAddress(params.getFromAddress(), params.getFromName()));

                // Set to
                msg.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));

                // Set BCC
                if (params.getCc() != null) {
                    msg.addRecipient(Message.RecipientType.CC, new InternetAddress(params.getCc()));
                }

                // Set BCC
                if (params.getBcc() != null) {
                    msg.addRecipient(Message.RecipientType.BCC, new InternetAddress(params.getBcc()));
                }

                // Set reply to
                if (params.getReplyTo() != null) {
                    msg.setReplyTo(new InternetAddress[] { new InternetAddress(params.getReplyTo()) });
                }

                String body = "";

                // Append header
                if (includeHeaderAndFooter) {
                    body += replacePlaceholders(MessageHeader.getContents(), vars);
                }

                // Append body
                body += replacePlaceholders(contents, vars);

                // Append footer
                if (includeHeaderAndFooter) {
                    body += replacePlaceholders(MessageFooter.getContents(), vars);
                }

                msg.setContent(body, params.getContentType());

                return msg;
            }
        } catch (Exception e) {
            // Error while building email
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Email params holder
     */
    public static class EmailParams {

        // Default values
        protected String fromName;

        protected String fromAddress;

        protected String subject;

        protected String cc;

        protected String bcc;

        protected String replyTo;

        protected String contentType = "text/html; charset=UTF-8";

        public EmailParams() {
        }

        public EmailParams(Map<String, String> vars) {
            if (vars.get("$FROM_NAME$") != null)
                fromName = vars.get("$FROM_NAME$");
            if (vars.get("$FROM_ADDRESS$") != null)
                fromAddress = vars.get("$FROM_ADDRESS$");
            if (vars.get("$SUBJECT$") != null)
                subject = vars.get("$SUBJECT$");
            if (vars.get("$CC$") != null)
                cc = vars.get("$CC$");
            if (vars.get("$BCC$") != null)
                bcc = vars.get("$BCC$");
        }

        public String getFromName() {
            return fromName != null ? fromName : AbstractEmailEngine.FROM_NAME;
        }

        public void setFromName(String fromName) {
            this.fromName = fromName;
        }

        public String getFromAddress() {
            return fromAddress != null ? fromAddress : AbstractEmailEngine.FROM_ADDRESS;
        }

        public void setFromAddress(String fromAddress) {
            this.fromAddress = fromAddress;
        }

        public String getSubject() {
            return subject != null ? subject : "";
        }

        public void setSubject(String subject) {
            this.subject = subject;
        }

        public String getCc() {
            return cc;
        }

        public void setCc(String cc) {
            this.cc = cc;
        }

        public String getBcc() {
            return bcc;
        }

        public void setBcc(String bcc) {
            this.bcc = bcc;
        }

        public String getReplyTo() {
            return replyTo;
        }

        public void setReplyTo(String replyTo) {
            this.replyTo = replyTo;
        }

        public String getContentType() {
            return contentType;
        }

        public void setContentType(String contentType) {
            this.contentType = contentType;
        }
    }
}
